-
Notifications
You must be signed in to change notification settings - Fork 15k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: preliminary support for //extensions #17440
Conversation
I know this is still a WIP but @'ing wg-upgrades anyway to get feedback from that team anyway for feedback on the idea of this feature in |
c1d32ae
to
c46b7e0
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This review was done as a group at the hackweek.
atom/browser/atom_browser_context.cc
Outdated
base::OnceClosure closure) { | ||
// This method is called for Extension supports, but tests do not need to | ||
// support exceptional CORS handling. | ||
base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, std::move(closure)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could a // TODO
be added here -- we probably do need to support these allow/block patterns
AtomExtensionsAPIProvider::AtomExtensionsAPIProvider() = default; | ||
AtomExtensionsAPIProvider::~AtomExtensionsAPIProvider() = default; | ||
|
||
// TODO(samuelmaddock): generate API features? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't understand this comment. What needs to be done here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AddShellAPIFeatures
is a code generated function sourced from _api_features.json. The extensions subsystem and Chrome have their own features. We might need to do the same here.
AddAtomManifestFeatures
, on line 32, is generated by the BUILD.gn file in this directory.
|
||
const std::string AtomExtensionsClient::GetProductName() { | ||
// TODO(samuelmaddock): | ||
return "app_shell"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should use atom again
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The issue here is that this in in common
and therefore can run in either process. We can't guarantee to have access to atom::Browser::Get()->GetName()
cc @deepak1556 @nornagon suggestions?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
where does this string end up? maybe just Electron
is sufficient?
// extensions, so we always return 1. Note that 0 is reserved for the global | ||
// world. | ||
// TODO(samuelmaddock): skip electron worlds | ||
return 10; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🤔
This should be calculated to skip the isolated world rather than a hardcoded magic number
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We'll want to use World::ISOLATED_WORLD_EXTENSIONS
030a062
to
8176fbd
Compare
To avoid editing the original PR body I'd like to suggest slightly modified user facing API. interface Extension {
id: string,
path: string,
manifest: chrome.Manifest
}
class Session {
/** Emitted when extension is installed and ready. */
on(event: 'chrome-extension-will-activate', listener: (event: Event, extension: Extension) => void): this;
on(event: 'chrome-extension-activated', listener: (event: Event, extension: Extension) => void): this;
on(event: 'chrome-extension-deactivated', listener: (event: Event, extension: Extension) => void): this;
/** This should reject non-absolute paths **/
loadChromeExtension(path: string): Extension;
removeChromeExtension(extensionId: string): void;
enableChromeExtension(extensionId: string): void;
disableChromeExtension(extensionId: string): void;
} Summary:
|
atom/browser/atom_browser_context.cc
Outdated
|
||
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS) | ||
// TODO: Why? | ||
extension_system_ = nullptr; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This originates from the extension shell code. It doesn't seem useful from a functional benefit, but maybe rather signifies to a reader that it should no longer be used within that context.
atom/browser/atom_browser_context.cc
Outdated
|
||
extension_system_ = static_cast<extensions::AtomExtensionSystem*>( | ||
extensions::ExtensionSystem::Get(this)); | ||
extension_system_->InitForRegularProfile(true /* extensions_enabled */); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we might need to implement AtomExtensionSystem::InitForIncognitoProfile
to fix tests failing at
[958:0428/030848.424091:FATAL:storage_frontend.cc(140)] Check failed: !browser_context_->IsOffTheRecord().
@samuelmaddock Will we be able to handle UI related things like |
Not with the currently introduced changes. Some I've thought through how I should mention that I've since stopped actively working on this PR as the project I needed it for is no longer using Electron. Without some kind of sponsorship, I don't see this changing. Electron maintainers have shown interest in merging the changes though. |
I've created a library for implementing some of Chrome APIs, maybe this could help: https://github.com/wexond/electron-extensions |
Okay, this is getting close to ready to land I think. There's still plenty of work left to do but we're approaching a good "step 1". TODO before landing:
(3) will mean that it's going to be easy for the extensions code to break unless we have a CI environment building with extensions enabled, so we'll have to stay on top of keeping it working by running tests on our local machines until we can enable the flag by default (and eventually remove the flag altogether). |
(1) above is fixed, and there are now a few simple tests. The mac build failure is the autoUpdater spec which is broken on PRs from forks. |
buildflags/buildflags.gni
Outdated
|
||
# Enable Chrome extensions support | ||
# TODO: Disable before initial merge | ||
enable_electron_extensions = true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
enable_electron_extensions = true | |
enable_electron_extensions = false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @nornagon for fixing this up. 🎉
(session.defaultSession as any).loadChromeExtension(path.join(fixtures, 'extensions', 'simple')) | ||
const w = new BrowserWindow({show: false}) | ||
const customSession = session.fromPartition(`persist:${require('uuid').v4()}`); | ||
(customSession as any).loadChromeExtension(path.join(fixtures, 'extensions', 'red-bg')) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should there be a TODO dropped in here to add type definitions for loadChromeExtension
when the extensions build flag is toggled on?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I expect the API surface will change substantially between now and then so I'm inclined to leave it for now.
@@ -0,0 +1,55 @@ | |||
// Copyright 2014 The Chromium Authors. All rights reserved. | |||
// Use of this source code is governed by a BSD-style license that can be | |||
// found in the LICENSE file. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it okay to leave these copyright headers introduced from the extensions shell code? Or should they be replaced with the GitHub copyright?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🤷♂
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have many examples in our code where we have left in the Chromium copyright and/or added additional copyright depending on the person who created the code (eg there is a Slack copyright in some files). All that to say, its fine to leave as is unless an author wants to add their copyright.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall LGTM. The only nit I would have is whether or not we should continue using the "Atom" prefix for new classes (vs "Electron" prefix).
@@ -0,0 +1,55 @@ | |||
// Copyright 2014 The Chromium Authors. All rights reserved. | |||
// Use of this source code is governed by a BSD-style license that can be | |||
// found in the LICENSE file. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have many examples in our code where we have left in the Chromium copyright and/or added additional copyright depending on the person who created the code (eg there is a Slack copyright in some files). All that to say, its fine to leave as is unless an author wants to add their copyright.
|
||
namespace extensions { | ||
|
||
AtomRuntimeAPIDelegate::AtomRuntimeAPIDelegate( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we are adding new classes, should we still use the "Atom" prefix or move over to "Electron" prefix?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought we were going to stop prefixing, that's what namespacing is for 😆
cc @deepak1556 I think we talked about this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
gonna leave this for now and it can get caught when we do the first sweep.
No Release Notes |
Anything new on this? I'd love to see this merged. I'd love to contribute but I'm not very well versed in C++ and C. |
@xylobol It is merged... |
I can't believe I missed that. I need to stop looking through PRs before I've had my morning drink. |
Description of Change
Overview
These are the initial, exploratory changes for adding support for Chrome extensions using the
//extensions
dependency from Chromium's source code. This dependency is meant to allow embedders of Chromium the ability to add extension support for their project.Within the Electron community, there are several projects with their own implementation of Chrome extensions. No such implementation is complete and ends up duplicating the work of other implementations.
The goal of these changes are to introduce the first steps towards a more complete, official implementation of Chrome extensions for Electron-based projects.
Summary of changes
What's included
What's not included (yet)
What won't be included
Usage
Currently an extension can be loaded by providing a
--load-extension=/absolute/path/to/extension
switch. This is planned to be superseded by JavaScript bindings prior to merging.Architecture
The file and code additions to this PR are mostly sourced from the
//src/extensions/shell
project.In other words, the changes in this PR are mostly necessary boilerplate copied from app_shell to embed extensions.
app_shell implements support for Chrome Apps while we want support Chrome Extensions (differences). Luckily they both share a majority of the same core APIs. The main addition we required was to create an instance of
SharedUserScriptMaster
. The history of commits provide a good timeline of APIs added.Below are some of the notable classes added or changed as part of embedding extensions.
Browser
The entry point of changes for the browser process can be found in
atom_browser_main_parts.cc
.SharedUserScriptMaster
AtomExtensionSystem
Responsible for creating an instance of
SharedUserScriptMaster
. Globally accessible usingextensions::ExtensionSystem::Get(browser_context)
. Will likely be used by Electron JavaScript bindings for managing extensions.AtomExtensionLoader
AtomExtensionsBrowserClient
AtomBrowserContext
PrefRegistrySimple
andPrefRegistrySyncable
(which inheritsPrefRegistrySimple
).Common
AtomExtensionsClient
ExtensionsClient
singleton for providing common global APIs between the browser and renderer process. This is where we can add whatchrome.*
API features we choose to support for Electron.There's a bit of code generation that happens for implementing common extension features. This is done by atom/common/extensions/api/BUILD.gn which sources
_manifest_features.json
. For now, this only generates a manifest feature for content scripts. The config came from Chrome's_manifest_features.json
.Renderer
The entry point of changes for the renderer process can be found in
renderer_client_base.cc
.AtomExtensionsRendererClient
extensions::Dispatcher
reference sends events to the rest of the extensions system.Bindings API design (WIP)
As extensions seem to be tied closely to a
BrowserContext
, it might be a good idea to provide methods on theSession
API. This is the approach that the Muon fork took.Roadmap to merging
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
guardsShell*
classes toAtom*
Followup roadmap
BrowserContext
schrome.*
APIsChecklist
npm test
passesRelease Notes
Notes: no-notes
Initial merge won't allow developers to use these features just yet.